rust:axum+sqlx实战学习笔记1

您所在的位置:网站首页 every 英语怎么读 rust:axum+sqlx实战学习笔记1

rust:axum+sqlx实战学习笔记1

2023-02-21 01:11| 来源: 网络整理| 查看: 265

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情 

最近工作颇为清(摸)闲(鱼),既然如此,那就开个新坑。学习一下如何在rust进行简单的web后端crud。

首先上主角,当然是看我们需要用到哪些crate库:

tokio = {version = "1.20.0", features = ["full"]} axum = {version = "0.5.13", features = ["headers"]} sqlx = { version = "0.6.0", features = [ "runtime-tokio-rustls" ,"mysql","chrono"] } once_cell = "1.13.0" serde = {version = "1.0.140", features = ['derive']} serde_json = "1.0.82" tracing = "0.1.36" tracing-subscriber = {version = "0.3.15", features = ["env-filter"]} dotenv = "0.15.0" jsonwebtoken = "8.1.1" chrono = { version = "0.4.19",features = ["serde"] } 复制代码 Tokio异步运行时,rust目前最流行,最有名气的异步库。 axun,Tokio系旗下的web框架,这次就是要体验一下Tokio全家桶 sqlx 异步数据库框架,并不是orm框架那种,没有DSL,用户自己编写sql语句,将查询结果按列取出或映射到struct上 once_cell初始化全局变量库 serde、serde_json序列化专用库 tracing、tracing-subscriber,日志库 dotenv环境变量库 jsonwebtoken jwt认证库 chrono时间库

在正式开始之前,先看一下axum官方的例子:

use axum::{ routing::{get, post}, http::StatusCode, response::IntoResponse, Json, Router, }; use serde::{Deserialize, Serialize}; use std::net::SocketAddr; #[tokio::main] async fn main() { // initialize tracing //启动日志记录 tracing_subscriber::fmt::init(); // build our application with a route //构建路由 let app = Router::new() // `GET /` goes to `root` .route("/", get(root)) // `POST /users` goes to `create_user` .route("/users", post(create_user)); // run our app with hyper // `axum::Server` is a re-export of `hyper::Server` //服务端口 let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); tracing::debug!("listening on {}", addr); //启动服务 axum::Server::bind(&addr) .serve(app.into_make_service()) .await .unwrap(); } // basic handler that responds with a static string //handler函数 async fn root() -> &'static str { "Hello, World!" } //handler函数 async fn create_user( // this argument tells axum to parse the request body // as JSON into a `CreateUser` type Json(payload): Json, ) -> impl IntoResponse { // insert your application logic here let user = User { id: 1337, username: payload.username, }; // this will be converted into a JSON response // with a status code of `201 Created` (StatusCode::CREATED, Json(user)) } // the input to our `create_user` handler #[derive(Deserialize)] struct CreateUser { username: String, } // the output to our `create_user` handler #[derive(Serialize)] struct User { id: u64, username: String, } 复制代码

通过官方例子,我们对axum的基本结构有了一个大概的了解。用route函数设置路由,参数为路由路径和handler函数。至于什么是handler函数? 再来看axum文档中对handler的定义:

image.png

全是英文看不懂?其实我也不懂,靠着翻译和自己的理解。用人话来说,handler是一个异步函数用来处理程序逻辑并且返回响应内容。也就是说,我们在handler中处理路由的逻辑并返回内容或者是报错信息。

接下来我们的crud基本就是围绕handler函数的处理了。从create_user函数中,能看到一个完整的handler处理函数。

先看入参,也就是axum从Request请求中获取参数的办法,用axum里的概念叫Extract(提取解析)。

一、从path中提取参数

.route("/user/:id", get(user_info)) // eg: /user/1,将解析出id=1 async fn user_info(Path(id): Path) -> String { format!("user id:{}", id) } 复制代码

通过正则匹配获取路由路径中的值,不仅可以获取单个值,也可以匹配多个值

.route("/person/:id/:age", get(person)) // eg: /person/12/3,将解析出id=12, age=30 async fn person(Path((id, age)): Path) -> String { format!("id:{},age:{}", id, age) } 复制代码

也可以封装成一个struct进行匹配

.route("/path_req/:a/:b/:c/:d", get(path_req)) #[derive(Deserialize)] struct SomeRequest{ a: String, b: i32, c: String, d: u32, } // eg: path_req/a1/b1/c1/d1 async fn path_req(Path(req): Path) -> String { format!("a:{},b:{},c:{},d:{}", req.a, req.b, req.c, req.d) } 复制代码

二、从Url获取参数

.route("/query_req", get(query_req)) #[derive(Deserialize)] struct SomeRequest{ a: String, b: i32, c: String, d: Option, } //eg: query_req/?a=test&b=2&c=abc&d=80 async fn query_req(Query(args): Query) -> String { format!("a:{},b:{},c:{},d:{}", args.a, args.b, args.c, args.d) } 复制代码

聪明的小伙伴肯定发现了,怎么这个struct好像不对劲?里面有值是Option?因为如果希望有些参数可为空,可以把相应的字段改成Option。

如果想获取所有的QueryString参数,可以用HashMap进行映射:

.route("/query", get(query)) //eg: query?a=1&b=1.0&c=xxx async fn query(Query(params): Query) -> String { for (key, value) in ¶ms { println!("key:{},value:{}", key, value); } format!("{:?}", params) } 复制代码

三、从Form表单获取提取参数

.route("/form", post(form_request)) #[derive(Deserialize)] struct SomeRequest2 { a: Option, b: Option, c: Option, d: Option, } // 表单提交 async fn form_request(Form(model): Form) -> String { format!( "a:{},b:{},c:{},d:{}", model.a.unwrap_or_default(), model.b.unwrap_or(-1), //b缺省值指定为-1 model.c.unwrap_or_default(), model.d.unwrap_or_default()) } 复制代码

四、从applicataion/json获取参数

.route("/json", post(json_request)) // json提交 async fn json_request(Json(model): Json) -> String { format!("a:{},b:{},c:{},d:{}", model.a, model.b, model.c, model.d) } 复制代码

五、获取所有请求头

.route("/header", get(get_all_header)) /** * 获取所有请求头 */ async fn get_all_header(headers: HeaderMap) -> String { for (key, value) in &headers { println!("key:{:?} , value:{:?}", key, value); } format!("{:?}", headers) } 复制代码

如果像获取指定请求头参数,可以这样。提取指定header头,比如user-agent

.route("/user_agent", get(get_user_agent_header)) /** * 获取http headers中的user_agent头 */ async fn get_user_agent_header(TypedHeader(user_agent): TypedHeader) -> String { user_agent.to_string() } 复制代码

如何想要获取cookie,可以这样写:

async fn user_center(headers: HeaderMap) -> Result


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3